/*
 * Copyright (C) 2021 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package io.sentry;

import io.sentry.protocol.SdkVersion;
import io.sentry.protocol.SentryId;
import io.sentry.util.Objects;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

/**
 * SentryEnvelope
 *
 * @since 2021-06-02
 */
@ApiStatus.Internal
public final class SentryEnvelope {
    // types: session_batch, session, event, attachment
    // an envelope cannot have 2 events, but eg multiple sessions
    private final @NotNull SentryEnvelopeHeader header;
    private final @NotNull Iterable<SentryEnvelopeItem> items;

    /**
     * constructor
     *
     * @param header header
     * @param items items
     */
    public SentryEnvelope(
        final @NotNull SentryEnvelopeHeader header,
        final @NotNull Iterable<SentryEnvelopeItem> items) {
        this.header = Objects.requireNonNull(header, "SentryEnvelopeHeader is required.");
        this.items = Objects.requireNonNull(items, "SentryEnvelope items are required.");
    }

    /**
     * constructor
     *
     * @param eventId eventId
     * @param sdkVersion sdkVersion
     * @param items items
     */
    public SentryEnvelope(
        final @Nullable SentryId eventId,
        final @Nullable SdkVersion sdkVersion,
        final @NotNull Iterable<SentryEnvelopeItem> items) {
        header = new SentryEnvelopeHeader(eventId, sdkVersion);
        this.items = Objects.requireNonNull(items, "SentryEnvelope items are required.");
    }

    /**
     * constructor
     *
     * @param eventId eventId
     * @param sdkVersion sdkVersion
     * @param item item
     */
    public SentryEnvelope(
        final @Nullable SentryId eventId,
        final @Nullable SdkVersion sdkVersion,
        final @NotNull SentryEnvelopeItem item) {
        Objects.requireNonNull(item, "SentryEnvelopeItem is required.");
        header = new SentryEnvelopeHeader(eventId, sdkVersion);
        final List<SentryEnvelopeItem> sentryEnvelopeItems = new ArrayList<>(1);
        sentryEnvelopeItems.add(item);
        this.items = sentryEnvelopeItems;
    }

    public @NotNull Iterable<SentryEnvelopeItem> getItems() {
        return items;
    }

    public @NotNull SentryEnvelopeHeader getHeader() {
        return header;
    }

    /**
     * create SentryEnvelope instance from args
     *
     * @param serializer serializer
     * @param session session
     * @param sdkVersion sdkVersion
     * @return SentryEnvelope
     * @throws IOException e
     */
    public static @NotNull SentryEnvelope from(
        final @NotNull ISerializer serializer,
        final @NotNull Session session,
        final @Nullable SdkVersion sdkVersion)
        throws IOException {
        Objects.requireNonNull(serializer, "Serializer is required.");
        Objects.requireNonNull(session, "session is required.");
        return new SentryEnvelope(
            null, sdkVersion, SentryEnvelopeItem.fromSession(serializer, session));
    }

    /**
     * create SentryEnvelope instance from args
     *
     * @param serializer serializer
     * @param event event
     * @param sdkVersion sdkVersion
     * @return SentryEnvelope
     * @throws IOException e
     */
    public static @NotNull SentryEnvelope from(
        final @NotNull ISerializer serializer,
        final @NotNull SentryBaseEvent event,
        final @Nullable SdkVersion sdkVersion)
        throws IOException {
        Objects.requireNonNull(serializer, "Serializer is required.");
        Objects.requireNonNull(event, "item is required.");

        return new SentryEnvelope(
            event.getEventId(), sdkVersion, SentryEnvelopeItem.fromEvent(serializer, event));
    }
}
